#include "sbrush_spectral_model.h"

#include <fstream>

using namespace std;
using namespace sbrush;


SmsCorruptFile::SmsCorruptFile() 
:	SmsError("corrupt sms file")
{
}

SmsCorruptFile::~SmsCorruptFile() throw() {
}

SpectralModel::SpectralModel(const SpectralModel& copy)
:	m_Header(NULL) {
	*this = copy;
}

SpectralModel& SpectralModel::operator=(const SpectralModel& rhs) {
	if (this == &rhs) {
		return *this;
	}
	
	clear();
	if (rhs.m_Header != NULL) {
		m_Header = (SMS_Header*)malloc(rhs.m_Header->iHeadBSize);
		if (m_Header == NULL) {
			throw FailedAlloc();
		}
		memcpy(m_Header, rhs.m_Header, rhs.m_Header->iHeadBSize);
	}
	
	for (size_t i = 0; i < rhs.m_Frames.size(); i++) {
		auto_ptr<SMS_Data> data(new SMS_Data);
		Sms::initEmptyFrame(*data);
		if (rhs.m_Frames[i] != NULL) {
			Sms::copy(*data, *rhs.m_Frames[i]);
			m_Frames.push_back(data.release());
		}
	}

	return *this;
}

SpectralModel::SpectralModel() 
:	m_Header(NULL)
{
}

auto_ptr<SpectralModel> SpectralModel::read(const char* filename) {
//	auto_ptr<SpectralModel> model(new SpectralModel());
//	FILE* pSmsFile;
//	int err = sms_getHeader(const_cast<char*>(filename),
//							&model->m_Header, 
//							&pSmsFile);
//	if (err != SMS_OK) {
//		fclose(pSmsFile);
//		throw SmsCorruptFile();
//	}
//	
//	for(unsigned frame = 0; frame < model->m_Header->nFrames; frame++) {
//		auto_ptr<SMS_Data> smsFrame(new SMS_Data);
//		err = sms_allocFrameH(model->m_Header, smsFrame.get());
//		if (err != SMS_OK) {
//			throw SmsCorruptFile();
//		}
//		err = sms_getFrame(pSmsFile, model->m_Header, frame, smsFrame.get());
//		if (err != SMS_OK) {
//			sms_freeFrame(smsFrame.get());
//			throw SmsCorruptFile();
//		}
//		model->m_Frames.push_back(smsFrame.release());
//	}
//	
//	return model;
	ifstream ifs(filename, ios::binary);
	ifs.exceptions(ios::badbit);
	return SpectralModel::inflate(ifs);
}

auto_ptr<SpectralModel> SpectralModel::inflate(istream& binaryStream) {
	auto_ptr<SpectralModel> model(new SpectralModel());
	Sms::inflateHeader(model->m_Header, binaryStream);
	for (unsigned frame = 0; frame < model->m_Header->nFrames; frame++) {
		auto_ptr<SMS_Data> smsFrame(new SMS_Data);
		Sms::initEmptyFrame(*smsFrame);
		Sms::inflateData(*(model->m_Header), *smsFrame, binaryStream);
		model->m_Frames.push_back(smsFrame.release());
	}
	return model;
}

bool SpectralModel::write(const char* filename) {
	ofstream ofs(filename, ios::binary | ios::trunc);
	serialize(ofs);
	return (ofs.is_open() && ofs.good());
}

void SpectralModel::serialize(ostream& binaryStream) const {
	Sms::serializeHeader(*m_Header, binaryStream);
	for (size_t i = 0; i < m_Frames.size(); i++) {
		Sms::serializeData(*m_Header, *m_Frames[i], binaryStream);
	}
}

SpectralModel::~SpectralModel() throw() {
	try {
		clear();
	}
	catch (...) {
	}
}

const SMS_Header* SpectralModel::header() const {
	return m_Header;
}

size_t SpectralModel::getNumFrames() const {
	return m_Frames.size();
}

const SMS_Data& SpectralModel::getFrame(size_t idx) const {
	return *m_Frames.at(idx);
}
	
void SpectralModel::clear() {
	for (size_t frame = 0; frame < m_Frames.size(); frame++) {
		sms_freeFrame(m_Frames[frame]);
		delete m_Frames[frame];
	}
	m_Frames.clear();
	free(m_Header);
	m_Header = NULL;
}